import Foundation

extension String {
    
    /// 国际化扩展
    var localized: String {
        LanguageManager.shared.localize(string: self, bundle: Bundle.main)
    }

    /// 带参数的国际化
    func localized(_ arguments: CVarArg...) -> String {
        LanguageManager.shared.localize(string: self, bundle: Bundle.main, arguments: arguments)
    }

    /// 截取字符串
    /// - Parameters:
    ///   - begin: 开始截取的索引
    ///   - count: 需要截取的个数
    /// - Returns: 字符串
    func substring(start: Int, _ count: Int) -> String {
        let begin = index(startIndex, offsetBy: max(0, start))
        let end = index(startIndex, offsetBy: min(count, start + count))
        return String(self[begin..<end])
    }
    
    func toDictionary() -> [String : Any]? {
        
        var result: [String : Any]?
        guard !self.isEmpty else { return result }
        
        guard let dataSelf = self.data(using: .utf8) else {
            return result
        }
        
        if let dic = try? JSONSerialization.jsonObject(with: dataSelf,
                                                       options: .mutableContainers) as? [String : Any] {
            result = dic
        }
        return result
        
    }
}

extension String {
    
    func widthWithLimit(_ size:CGSize, font:UIFont) -> CGFloat {
        return sizeWithLimit(size, font: font).width
    }
    
    func heightWithLimit(width: CGFloat, font:UIFont) -> CGFloat {
        let label = UILabel()
        label.text = self
        label.font = font
        label.numberOfLines = 0
        label.frame.size.width = width
        label.sizeToFit()
        return label.frame.height
    }
    
    func sizeWithLimit(_ size:CGSize, font:UIFont) -> CGSize {
        guard self.count > 0 else {
            return CGSize.zero
        }
        let text = self as NSString
        let rect = text.boundingRect(with: size, options: .usesLineFragmentOrigin, attributes: [NSAttributedString.Key.font : font], context: nil)
        return rect.size
    }
    
    public func getStringHeight(string:String? = nil,font:UIFont,width:CGFloat) ->CGFloat {
        return sizeWithLimit(CGSize(width: width, height: 100000), font: font).height
    }
}

extension NSAttributedString {
    
    func heightWithSizeThatFits(constrainedToWidth width: CGFloat, font: UIFont) -> CGFloat {
        let label = UILabel()
        label.attributedText = self
        label.font = font
        label.numberOfLines = 0
        label.frame.size.width = width
        label.sizeToFit()
        return label.frame.height
    }
    
    func widthWithSizeThatFits(constrainedToSize size: CGSize, font: UIFont) -> CGFloat {
        let label = UILabel()
        label.attributedText = self
        label.font = font
        label.numberOfLines = 0
        label.frame.size = size
        label.sizeToFit()
        return label.frame.height
    }
    
    func height(constrainedToWidth width: CGFloat) -> CGFloat {
        let textContainer = NSTextContainer(size: CGSize(width: width, height: .greatestFiniteMagnitude))
        let layoutManager = NSLayoutManager()
        let textStorage = NSTextStorage(attributedString: self)
        
        layoutManager.addTextContainer(textContainer)
        textStorage.addLayoutManager(layoutManager)
        
        let boundingRect = layoutManager.usedRect(for: textContainer)
        
        return boundingRect.height
    }
    
    func width(constrainedToHeight height: CGFloat) -> CGFloat {
        let textContainer = NSTextContainer(size: CGSize(width: .greatestFiniteMagnitude, height: height))
        let layoutManager = NSLayoutManager()
        let textStorage = NSTextStorage(attributedString: self)
        
        layoutManager.addTextContainer(textContainer)
        textStorage.addLayoutManager(layoutManager)
        
        let boundingRect = layoutManager.usedRect(for: textContainer)
        
        return boundingRect.width
    }
    
    func boundingRect(for size: CGSize) -> CGRect {
        let options: NSStringDrawingOptions = [.usesLineFragmentOrigin, .usesFontLeading]
        let boundingRect = self.boundingRect(
            with: size,
            options: options,
            context: nil
        )
        return boundingRect
    }
    
    func width(for height: CGFloat) -> CGFloat {
        let size = CGSize(width: CGFloat.greatestFiniteMagnitude, height: height)
        let boundingRect = self.boundingRect(for: size)
        return ceil(boundingRect.width)
    }
    
    func height(for width: CGFloat) -> CGFloat {
        let size = CGSize(width: width, height: CGFloat.greatestFiniteMagnitude)
        let boundingRect = self.boundingRect(for: size)
        return ceil(boundingRect.height)
    }
    
}
